home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #30 (Mar 88) / Quicktraps / quicktrap.a
Text File  |  1987-10-24  |  8KB  |  227 lines

  1. ; Macintosh Toolbox and OS-trap bypass routines.
  2. ; Copyright © 1987 Michael S. Morton
  3. ;
  4. ; History:    10-May-87 - MM - Initial version.
  5. ;        22-Oct-87 - MM - Neatened for publication.
  6.  
  7.     BLANKS    ON
  8.     STRING    ASIS
  9.     PRINT    OFF
  10.     LOAD    'tlAsmSyms.sym'
  11.     PRINT    ON
  12.  
  13.     ; Impure code!  Should be in a segment which is locked in memory.
  14.     SEG    'LOCKDSEG'        ; *** change to a locked segment ***
  15.  
  16. ;--------------------------------------------------------------------------
  17. ; Each Toolbox routine starts out life as:
  18. ;        2 <pure copy of trap word>
  19. ;    entry:    2 <trap word with auto-pop bit>
  20. ;        4 <four bytes unused>
  21. ;
  22. ; The evaluator changes this to:
  23. ;        2 <pure copy of trap word>
  24. ;    entry:    6 JMP      <actual address>
  25. ;
  26. ; Either form is callable with a JSR because the former includes the “auto-pop”
  27. ; bit, so the Toolbox routine returns to its caller’s caller.  Offsets are:
  28.  
  29. tTrap:        EQU    0        ; pure copy of trap
  30. tJump:        EQU    2        ; JMP xxx.L instruction
  31. tAddress:    EQU    4        ; address to jump to
  32. tLength:    EQU    8        ; length of one block
  33.  
  34. ;   The “qtTool” macro generates code for one “qt” Toolbox routine.
  35. ;
  36. ; args:     routine -    Name for routine.  Typically “qt” plus trap name.
  37. ;        trap    -    Name of the trap, eg, “_MoveTo”.
  38.  
  39.     MACRO
  40.     qtTool
  41.         EXPORT    &Syslst[1]    ; define the “qtXXX” routine globally
  42.         &Syslst[2]        ; first, a pure copy of the trap word
  43. &Syslst[1]    &Syslst[2]  autoPop    ; entry: if not overwritten, just trap
  44.         ds.b    4        ; reserve room for overwriting
  45.     ENDM
  46.  
  47. ;--------------------------------------------------------------------------
  48. ; Each OS trap bypass routine is 28 bytes long.  The unevaluated routine is:
  49. ;        2 <pure copy of trap word>
  50. ;    entry:    2 <trap word>            ; only this part…
  51. ;        2 RTS                ; …gets executed before eval
  52. ;        4 MOVE.W  #<xxx>, D1        ; trap word patched here
  53. ;        4 MOVE.W  #<xxx>, D2        ; trap number patched here
  54. ;        6 JSR      xxx.L            ; routine address patched here
  55. ;        4 MOVEM.L (SP)+, D1-D2/A1-A2    ; register list patched here
  56. ;        2 TST.W   D0            ; set condition codes
  57. ;        2 RTS                ; and return
  58. ; After the evaluator is done, the routine becomes:
  59. ;        2 <pure copy of trap word>
  60. ;    entry:    4 MOVEM.L D1-D2/A1-A2, -(SP)    ; (saves A0 too, if bit 8 set)
  61. ;        4 MOVE.W  #<trapword>, D1     ; get trap word in D1
  62. ;        4 MOVE.W  #<trapword & $01FF>, D2 ; …and trap number
  63. ;        6 JSR      xxx.L            ; call the routine
  64. ;        4 MOVEM.L (SP)+, D1-D2/A1-A2    ; (gets A0 too, if bit 8 set)
  65. ;        2 TST.W   D0            ; set condition codes
  66. ;        2 RTS                ; and return
  67.  
  68. oTrap:        EQU    0        ; original trap word
  69. oSave:        EQU    2        ; for MOVEM.L xxx, -(SP) to go
  70. oTrapWord:    EQU    8        ; for trap word in MOVE.W #xxx, D1
  71. oTrapNum:    EQU    12        ; for trap number in MOVE.W #xxx, D2
  72. oAddress:    EQU    16        ; address to jump to
  73. oRestore:    EQU    22        ; for second copy of MOVEM regs list
  74. oLength:    EQU    28        ; length of one block
  75.  
  76. ;   The “qtOS” macro generates code for one “qt” OS routine.
  77. ;
  78. ; args:     routine -    Name for trap routine.  Typically “qt” plus trap name.
  79. ;        trap    -    Name of the trap, eg, “_GetHandleSize”.
  80.  
  81.     MACRO
  82.     qtOS
  83.         EXPORT    &Syslst[1]    ; define the “qtXXX” routine globally
  84.         &Syslst[2]        ; pure copy of trap word
  85. &Syslst[1]    &Syslst[2]        ; entry: if not overwritten, just trap…
  86.         RTS            ; …and return
  87.         MOVE.W    #$5555, D1    ; get trap word in D1, for OS routine
  88.         MOVE.W    #$5555, D2    ; …and trap number
  89.         JSR    $55555555    ; leave space for a longword address
  90.         MOVEM.L (SP)+, D1-D2/A1-A2 ; assume A0 not in the register list
  91.         TST.W    D0        ; set condition codes
  92.         RTS            ; and return
  93.     ENDM
  94.  
  95. ;--------------------------------------------------------------------------
  96. ; Resource type and ID for the flag used to disable the trickery.
  97.  
  98. qtrpType:    EQU    'QTRP'            ; resource type for flag
  99. qtrpId:     EQU    257            ; resource ID for flag
  100.  
  101.  
  102. ;   qtEval
  103. ;
  104. ; description:
  105. ;    Update the routines so they jump directly into the ROM, or wherever.
  106. ;    This routine should be called at startup, and each time the application
  107. ;    thinks anyone has (or might have) called SetTrapAddress.
  108. ;
  109. ; uses:    (no registers)
  110.  
  111. qtEval:     PROC    EXPORT
  112.  
  113. ; Stuff used in patching together routines:
  114. jmpInst:    EQU    $4EF9        ; opcode word of JMP xxx.L
  115.  
  116. OSregs: REG    D1-D2/A1-A2        ; registers saved by OS dispatcher
  117. OSregs2:REG    D1-D2/A0-A2        ; registers saved when bit 8 is zero
  118.  
  119.     MOVEM.L D0-D2/A0-A2, -(SP)    ; save caller’s registers
  120.  
  121.     ; First, see if we’ve already been told not to do our thing:
  122.     LEA    qtEnabled, A2        ; point to the flag
  123.     TST.B    (A2)            ; have we snuffed it already?
  124.     BEQ    evalEnd         ; yes: nothing to do
  125.  
  126.     ; Second, decide if the resource flag allows us to map/cache.
  127.     SUBQ    #4, SP            ; make room for function result
  128.     MOVE.L    #qtrpType, -(SP)    ; pass the type…
  129.     MOVE.W    #qtrpId, -(SP)        ; …and ID
  130.     _GetResource            ; try to find our flag
  131.     MOVE.L    (SP)+, A0        ; pop result…
  132.     MOVE.L    A0, D0            ; …and test for NIL
  133.     BEQ.S    evalTurnOff        ; no such thing?  go flag this and exit
  134.  
  135.     MOVE.L    (A0), A1        ; deref. handle; point to rsrc with A0
  136.     MOVE.W    (A1), D2        ; pick up first word, to check later
  137.     MOVE.L    A0, -(SP)        ; pass handle…
  138.     _ReleaseResource        ; …and get rid of it
  139.  
  140.     TST.W    D2            ; now check -- did rsrc start with zero?
  141.     BNE.S    evalTurnOff        ; …no: we don’t yet do selective disable
  142.  
  143.     ; Nothing forbids hackery.  Evaluate all the toolbox bypass routines.
  144.     LEA    qtToolStart, A1     ; point to first routine
  145.     LEA    qtToolEnd, A2        ; point to just after last routine
  146.     MOVE.W    #jmpInst, D1        ; get a JMP xxx.L instruction
  147.     BRA.S    toolEnd         ; check for no routines
  148.  
  149. toolLp:    MOVE.W    tTrap(A1), D0        ; pick up the trap number in D0.w
  150.     _GetTrapAddress newTool     ; ask where this routine lives
  151.     MOVE.L    A0, tAddress(A1)    ; store address first, THEN…
  152.     MOVE.W    D1, tJump(A1)        ; …the JMP, so routine’s always OK
  153.     ADDQ    #tLength, A1        ; advance to the next routine
  154.  
  155. toolEnd:CMP.L    A2, A1            ; at (or past) end of toolbox routines?
  156.     BLO.S    toolLp            ; nope: go evaluate another one
  157.  
  158.     ; Evaluate all the OS bypass routines.
  159.     LEA    qtOSStart, A1        ; point to first…
  160.     LEA    qtOSEnd, A2        ; …and to just after last
  161.     BRA.S    osEnd            ; handle degenerate case
  162.  
  163. osLoop: MOVE.W    oTrap(A1), D0        ; pick up trap number
  164.     MOVE.W    D0, D2            ; copy it for later use (BTST, etc.)
  165.     _GetTrapAddress newOS        ; find where the routine lives
  166.     MOVE.L    A0, oAddress(A1)    ; save routine address in JMP xxx.L
  167.  
  168.     MOVE.W    D2, oTrapWord(A1)    ; fill in MOVE.W #trapword, D1
  169.     AND.W    #$01FF, D2        ; get just the trap number
  170.     MOVE.W    D2, oTrapNum(A1)    ; and store that in MOVE.W #trapnum, D2
  171.  
  172.     ; Decide whether the saved registers include A0.
  173.     MOVE.L    OSent, D0        ; assume we want usual registers saved…
  174.     MOVE.L    OSexit, D1        ; …and restored
  175.     BTST    #8, D2            ; but should we save A0, too?
  176.     BNE.S    osLp1            ; nope: OSent’s registers are fine
  177.     MOVE.L    OSent2, D0        ; yep: use reg list which includes A0
  178.     MOVE.L    OSexit2, D1        ; …and ditto for one which saves A0
  179. osLp1:    MOVE.W    D1, oRestore(A1)    ; store register list for restore
  180.     MOVE.L    D0, oSave(A1)        ; lastly, get rid of 1st trap
  181.     ADD    #oLength, A1        ; advance to the next routine
  182.  
  183. osEnd:    CMP.L    A2, A1            ; at the end?
  184.     BLO.S    osLoop            ; nope: go do another
  185.  
  186. evalEnd:MOVEM.L (SP)+, D0-D2/A0-A2    ; restore caller’s registers
  187.     RTS
  188.  
  189.     ; Here when the resource forbids caching.  A2 points to the flag.
  190. evalTurnOff:
  191.     SF    (A2)            ; …disable it for faster call next time
  192.     BRA.S    evalEnd         ; clean up and exit
  193.  
  194.     ; *** Impure *** flag: 0 means mapping disabled; non-zero means enabled.
  195. qtEnabled:
  196.     DC.B    $FF,00            ; initially enabled; 2nd byte to align
  197.  
  198. ; Instructions and register lists to stick into OS routines.  Each is 2 words.
  199. OSent:    MOVEM.L OSregs, -(SP)
  200. OSent2:    MOVEM.L OSregs2, -(SP)
  201. OSexit: MOVEM.L (SP)+, OSregs
  202. OSexit2:MOVEM.L (SP)+, OSregs2
  203.  
  204. ; Toolbox trap replacement routines.  To be re-evaluated, these must be between
  205. ; qtToolStart and qtToolEnd.  Nothing else must be in here -- the evaluator
  206. ; walks through this as an array.
  207. qtToolStart:     ; Beginning of Toolbox trap replacement routines.
  208.  
  209.     qtTool    qtMoveTo,_MoveTo
  210.     qtTool    qtSetPort,_SetPort
  211.     ; …add your own here…
  212.  
  213. qtToolEnd:     ; End of Toolbox trap replacement routines.
  214.  
  215. ; OS trap replacement routines.  As with toolbox, keep only these in here.
  216. qtOSStart:     ; Beginning of OS trap replacement routines.
  217.  
  218.     qtOS    qtHLock,_HLock
  219.     qtOS    qtHUnlock,_HUnlock
  220.     ; …add your own here…
  221.  
  222. qtOSEnd:     ; End of OS trap replacement routines.
  223.  
  224.     END
  225.  
  226.  
  227.